<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset="utf-8"/>
    <title>点选图片验证码</title>
</head>

<style type="text/css">
    html{
        width: 100%;
        height: 100%;
        background-color: #16202f;
    }
    body{
        width: 100%;
        height: 100%;
        margin:0;
        padding:0;
        position: relative;
        overflow: hidden;
        font-family: "Arial", "Microsoft YaHei", "黑体", "宋体", sans-serif;
    }

    .wg-cap-root{
        width: 100%;
        height: 100%;
        display:-webkit-box;
        display:-webkit-flex;
        display:-ms-flexbox;
        display:flex;
        flex-direction: column;
        -webkit-box-align:center;
        -webkit-align-items:center;
        -ms-flex-align:center;
        align-items: center;
    }
    .wg-cap-container{
        position: relative;
        width: 330px;
        padding: 440px 15px 0 15px;
        height: 50px;
        margin: auto;
    }
    .wg-cap-container.wg-cap-dialog__active  .wg-cap-dialog {
        display: block;
    }

    @keyframes tinUpIn {
        0% { opacity:0; transform:scale(1) translateY(-500%); }
        /*50% { opacity:1; transform:scale(1.1) translateY(0); }*/
        /*70% { opacity:1; transform:scale(1.1) translateY(0); }*/
        /*90% { opacity:1; transform:scale(1.1) translateY(0);  }*/
        60% { opacity:1; transform:scale(1) translateY(0);  }
        80% { opacity:1; transform:scale(1) translateY(0); }
        100% { opacity:1; transform:scale(1) translateY(0); }
    }
    @-webkit-keyframes tinUpIn {
        0% { opacity:0; transform:scale(1) translateY(-500%); }
        /*50% { opacity:1; transform:scale(1.1) translateY(0); }*/
        /*70% { opacity:1; transform:scale(1.1) translateY(0); }*/
        /*90% { opacity:1; transform:scale(1.1) translateY(0);  }*/
        60% { opacity:1; transform:scale(1) translateY(0);  }
        80% { opacity:1; transform:scale(1) translateY(0); }
        100% { opacity:1; transform:scale(1) translateY(0); }
    }
    .wg-cap-container.wg-cap-dialog__active  .wg-cap-wrap{
        display: block;
        animation: tinUpIn 1s linear;
        -moz-animation: tinUpIn 1s linear;
        -webkit-animation: tinUpIn 1s linear;
    }
    .wg-cap-container .wg-cap-block{
        /*padding-top: 440px;*/
    }

    .wg-cap-dialog{
        position: fixed;
        z-index: 2000;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        display: none;
    }

    .wg-cap-wrap{
        position: absolute;
        bottom: -10px;
        z-index: 2001;
        display: none;

        padding: 15px;
        border: 1px solid rgba(206, 223, 254, 0.5);
        background: #ffffff;

        -webkit-border-radius: 10px;
        -moz-border-radius: 10px;
        border-radius: 10px;

        box-shadow: 0 0 20px rgba(100, 100, 100, 0.1);
        -webkit-box-shadow: 0 0 20px rgba(100, 100, 100, 0.1);
        -moz-box-shadow: 0 0 20px rgba(100, 100, 100, 0.1);

        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
    }
    .wg-cap-wrap__header{
        height: 50px;
        width: 100%;
        font-size: 15px;

        display:-webkit-box;
        display:-webkit-flex;
        display:-ms-flexbox;
        display:flex;
        -webkit-box-align:center;
        -webkit-align-items:center;
        -ms-flex-align:center;
        align-items: center;
    }
    .wg-cap-wrap__header span{
        padding-right: 5px;
    }
    .wg-cap-wrap__header span em{
        padding: 0 3px;
        font-weight: bold;
        color: #3e7cff;
        font-style: normal;
    }
    .wg-cap-wrap__header .wg-cap-wrap__image{
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        border-radius: 5px;
        overflow: hidden;
        text-align: center;
        line-height: 1;
    }
    .wg-cap-wrap__header .wg-cap-wrap__thumb.wg-cap-wrap__hidden{
        display: none;
    }

    .wg-cap-wrap__body{
        position: relative;
        width: 300px;
        height: 300px;
        display: -webkit-box;
        display: -moz-box;
        display: -ms-flexbox;
        display: -webkit-flex;
        display: flex;
        background: #34383e;
        margin: auto;
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        border-radius: 5px;
        overflow: hidden;
    }
    .wg-cap-wrap__body .wg-cap-wrap__picture{
        position: relative;
        z-index: 10;
        width: 300px;
        height: 300px;
        max-width: 100%;
        max-height: 100%;
        object-fit: cover;
        line-height: 300px;
        text-align: center;
    }
    .wg-cap-wrap__body .wg-cap-wrap__picture.wg-cap-wrap__hidden{
        display: none;
    }
    .wg-cap-wrap__body .wg-cap-wrap__loading{
        position: absolute;
        z-index: 9;
        top: 50%;
        left: 50%;
        width: 68px;
        height: 68px;
        margin-left: -34px;
        margin-top: -34px;
        line-height: 68px;
        text-align: center;
    }
    .wg-cap-wrap__body .wg-cap-wrap__dot{
        position: absolute;
        z-index: 10;
        width: 22px;
        height: 22px;
        color: #cedffe;
        background: #3e7cff;
        border: 2px solid #f7f9fb;
        line-height: 20px;
        text-align: center;
        -webkit-border-radius: 22px;
        -moz-border-radius: 22px;
        border-radius: 22px;
        cursor: default;
    }

    .wg-cap-wrap__footer {
        width: 100%;
        height: 40px;
        color: #34383e;
        display:-webkit-box;
        display:-webkit-flex;
        display:-ms-flexbox;
        display:flex;
        -webkit-box-align:center;
        -webkit-align-items:center;
        -ms-flex-align:center;
        align-items: center;
        padding-top: 15px;
    }
    .wg-cap-wrap__footer .wg-cap-wrap__ico{
        flex: 1;
    }
    .wg-cap-wrap__footer .wg-cap-wrap__ico img{
        width: 24px;
        height: 24px;
        color: #34383e;
        margin: 0 5px;
        cursor: pointer;
    }
    .wg-cap-wrap__footer .wg-cap-wrap__btn{
        width: 120px;
        height: 40px;
    }
    .wg-cap-wrap__footer .wg-cap-wrap__btn button{
        width: 100%;
        height: 40px;
        letter-spacing: 2px;
        text-align: center;
        padding: 9px 15px;
        font-size: 15px;
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        border-radius: 5px;
        display: inline-block;
        line-height: 1;
        white-space: nowrap;
        cursor: pointer;
        color: #fff;
        background-color: #409eff;
        border: 1px solid #409eff;
        -webkit-appearance: none;
        box-sizing: border-box;
        outline: none;
        margin: 0;
        transition: .1s;
        font-weight: 500;
        -moz-user-select: none;
        -webkit-user-select: none;
    }
    .wg-cap-wrap__footer .wg-cap-wrap__btn button:hover {
        background: #66b1ff;
        border-color: #66b1ff;
        color: #fff;
    }

    .wg-cap-btn {
        width: 100%;
        height: 48px;
    }
    .wg-cap-btn .wg-cap-btn__inner{
        width: 100%;
        height: 48px;
        position: relative;
        letter-spacing: 1px;
    }
    .wg-cap-btn .wg-cap-state__default, .wg-cap-btn .wg-cap-state__error, .wg-cap-btn .wg-cap-state__success, .wg-cap-btn .wg-cap-state__over{
        position: absolute;
        width: 100%;
        height: 48px;
        font-size: 13px;
        -webkit-border-radius: 5px;
        -moz-border-radius: 5px;
        border-radius: 5px;
        display: inline-block;
        line-height: 1;
        white-space: nowrap;
        cursor: pointer;
        -webkit-appearance: none;
        box-sizing: border-box;
        outline: none;
        margin: 0;
        transition: .1s;
        font-weight: 500;
        -moz-user-select: none;
        -webkit-user-select: none;

        display:-webkit-box;
        display:-webkit-flex;
        display:-ms-flexbox;
        display:flex;
        -webkit-box-align:center;
        -webkit-align-items:center;
        -ms-flex-align:center;
        align-items: center;
        justify-content: center;
        justify-items: center;

        visibility: hidden;
    }
    .wg-cap-btn .wg-cap-state__default{
        color: #3e7cff;
        border: 1px solid #50a1ff;
        background: #ecf5ff;
        box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
        -webkit-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
        -moz-box-shadow: 0 0 20px rgba(62, 124, 255, 0.1);
    }
    .wg-cap-btn .wg-cap-state__error{
        color: #ed4630;
        background: #fef0f0;
        border: 1px solid #ff5a34;
    }
    .wg-cap-btn .wg-cap-state__over{
        color: #ffa000;
        background: #fdf6ec;
        border: 1px solid #ffbe09;
    }
    .wg-cap-btn .wg-cap-state__success{
        color: #5eaa2f;
        background: #f0f9eb;
        border: 1px solid #8bc640;
        pointer-events: none;
    }
    .wg-cap-btn .wg-cap-active__default .wg-cap-state__default, .wg-cap-btn .wg-cap-active__error .wg-cap-state__error,.wg-cap-btn .wg-cap-active__over .wg-cap-state__over ,.wg-cap-btn .wg-cap-active__success .wg-cap-state__success {
        visibility: visible;
    }
    .wg-cap-btn .wg-cap-state__inner{
        display:-webkit-box;
        display:-webkit-flex;
        display:-ms-flexbox;
        display:flex;
        -webkit-box-align:center;
        -webkit-align-items:center;
        -ms-flex-align:center;
        align-items: center;
        justify-content: center;
        justify-items: center;
    }
    .wg-cap-btn .wg-cap-state__inner em{
        padding-left: 5px;
        color: #3e7cff;
        font-style: normal;
    }
    .wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico{
        position: relative;
        width: 24px;
        height: 24px;
        margin-right: 12px;
        font-size: 14px;
        display: inline-block;
        float: left;
        flex: 0;
    }
    .wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__ico img{
        width: 24px;
        height: 24px;
        float: left;
        position: relative;
        z-index: 10;
    }
    @keyframes ripple {
        0% { opacity: 0; }
        5% { opacity: 0.05; }
        20% { opacity: 0.35; }
        65% { opacity: 0.01;  }
        100% {
            transform: scaleX(2) scaleY(2);
            opacity: 0;
        }
    }
    @-webkit-keyframes ripple {
        0% { opacity: 0; }
        5% { opacity: 0.05; }
        20% { opacity: 0.35; }
        65% { opacity: 0.01;  }
        100% {
            transform: scaleX(2) scaleY(2);
            opacity: 0;
        }
    }
    .wg-cap-btn .wg-cap-btn__inner .wg-cap-btn__verify::after {
        background: #409eff;
        -webkit-border-radius: 50px;
        -moz-border-radius: 50px;
        border-radius: 50px;
        content: "";
        display: block;
        width: 24px;
        height: 24px;
        opacity: 0;
        position: absolute;
        top: 0;
        left: 0;
        z-index: 9;

        animation: ripple 1.3s infinite;
        -moz-animation: ripple 1.3s infinite;
        -webkit-animation: ripple 1.3s infinite;
        animation-delay: 2s;
        -moz-animation-delay: 2s;
        -webkit-animation-delay: 2s;
    }

    .wg-cap-tip{
        padding: 50px 20px 100px;
        font-size: 13px;
        color: #76839b;
        text-align: center;
        line-height: 180%;
        width: 100%;
        max-width: 680px;
    }
</style>

<body>
<div class="wg-cap-root">
    <div id="wg-cap-container" class="wg-cap-container">
        <div class="wg-cap-block">
            <!-- wrap -->
            <div id="wg-cap-wrap" class="wg-cap-wrap">
                <div class="wg-cap-wrap__header">
                    <span>请在下图<em>依次</em>点击：</span>
                    <img id="wg-cap-thumb" class="wg-cap-wrap__thumb" src="" alt="...">
                </div>
                <div class="wg-cap-wrap__body" id="wg-cap-wrap" >
                    <img id="wg-cap-image" class="wg-cap-wrap__picture" src="" alt="...">
                    <img class="wg-cap-wrap__loading" src="" alt="正在加载中...">
                    <div id="wg-cap-dots">
                        <!-- <div class="wg-cap-wrap__dot"><span>1</span></div> -->
                    </div>
                </div>
                <div class="wg-cap-wrap__footer">
                    <div class="wg-cap-wrap__ico">
                        <img id="wg-cap-close-btn" src="" alt="关闭">
                        <img id="wg-cap-refresh-btn" src="" alt="刷新">
                    </div>
                    <div class="wg-cap-wrap__btn">
                        <button id="wg-cap-check-btn">确认</button>
                    </div>
                </div>
            </div>
            <!-- dialog -->
            <div id="wg-cap-dialog" class="wg-cap-dialog"></div>
            <!-- button -->
            <div class="wg-cap-btn">
                <!-- wg-cap-active__default wg-cap-active__error wg-cap-active__over wg-cap-active__success--->
                <div id="wg-cap-btn-control" class="wg-cap-btn__inner wg-cap-active__default">
                    <div id="wg-cap-btn-default" class="wg-cap-state__default">
                        <!-- 初始状态 -->
                        <div class="wg-cap-state__inner">
                            <div class="wg-cap-btn__ico wg-cap-btn__verify">
                                <img src="">
                            </div>
                            <span class="wg-cap-btn__text">点击按键进行验证</span>
                        </div>
                    </div>
                    <div id="wg-cap-btn-error" class="wg-cap-state__error">
                        <!-- 验证失败状态 -->
                        <div class="wg-cap-state__inner">
                            <div class="wg-cap-btn__ico">
                                <img src="" alt="失败">
                            </div>
                            <span>验证失败 <em>点击重试</em></span>
                        </div>
                    </div>
                    <div id="wg-cap-btn-over" class="wg-cap-state__over">
                        <!-- 验证次数过多状态 -->
                        <div class="wg-cap-state__inner">
                            <div class="wg-cap-btn__ico">
                                <img src="" alt="失败">
                            </div>
                            <span>点击次数过多 <em>点击重试</em></span>
                        </div>
                    </div>
                    <div class="wg-cap-state__success">
                        <!-- 验证成功状态 -->
                        <div class="wg-cap-state__inner">
                            <div class="wg-cap-btn__ico">
                                <img src="" alt="成功">
                            </div>
                            <span>已验证成功</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- tip -->
    <div class="wg-cap-tip">Demo: 本页面为效果演示，在接入时处理对应事件、状态的显示和微调整样式融合到实际项目即可；后端使用Go，前端使用Js，也可以接入Vue,React,Angular...等MVVM框架项目中使用</div>
</div>
</body>

<script type="text/javascript">

    /** =================================================================================
     * @Description: 此DEMO前端使用原生方式编写，为了让开发者更好理解使用，在本实例中不使用不依懒JQ、Vue等前端库
     * 如果你在 VUE、React、Angular等项目中使用，直接拷贝代码修改一下做成组件即可
     * ==================================================================================
     */

    /**
     * @Description:  封装Ajax
     * @return post Function
     get Function
     */
    const Ajax = (function () {
        var xhr
        var requestArr = []

        /**
         * @Description: 初始化
         */
        function __initialize() {
            if(window.XMLHttpRequest){
                xhr = new XMLHttpRequest()
            } else if(window.ActiveObject){
                xhr = new ActiveXobject('Microsoft.XMLHTTP')
            }
        }

        /**
         * @Description: 请求处理
         * @param options
         */
        function requestHandler(options){
            // 调用函数时如果options没有指定，就给它赋值{},一个空的Object
            options = options || {}
            // 请求格式GET、POST，默认为GET
            options.type = (options.type || "GET").toUpperCase()
            // 响应数据格式，默认json
            options.dataType = options.dataType || "json"
            // options.data请求的数据
            const params = ajaxFormatParams(options.data)

            // 启动并发送一个请求
            if(options.type === "GET"){
                xhr.open("GET", options.url+"?" + params,true);
                xhr.send(null);
            }else if(options.type === "POST"){
                xhr.open("post",options.url,true);
                // 设置表单提交时的内容类型
                // Content-type数据请求的格式
                xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
                xhr.send(params);
            }

            xhr.timeout = options.timeout

            // 设置有效时间
            setTimeout(function(){
                if(xhr.readySate !== 4){
                    xhr.abort();
                }
            }, options.timeout)

            // onreadystatechange
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    var status = xhr.status;
                    if(status >= 200 && status < 300 || status === 304){
                        var data = xhr.responseText
                        if (isJSONString(data)) {
                            data = eval("("+xhr.responseText+")")
                        }
                        options.success&&options.success(data, xhr.responseXML);
                    }else{
                        options.error&&options.error(status);
                    }
                }
                options.complete&&options.complete(status);
            }
        }

        /**
         * @Description: 是否是Json格式
         * @param str
         */
        function isJSONString(str) {
            if (typeof str == 'string') {
                try {
                    var obj = JSON.parse(str)
                    return typeof obj == 'object' && obj
                } catch(e) {}
            }

            return false
        }

        /**
         * @Description: Ajax格式化请求参数
         * @param data
         */
        function ajaxFormatParams(data){
            var arr = [];
            for(var name in data){
                arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]))
            }
            arr.push(("v=" + Math.random()).replace(".",""))
            return arr.join("&")
        }

        /**
         * @Description: 处理Post请求
         * @param url
         * @param data
         * @param success
         * @param error
         * @param complete
         */
        function handlePost (url, data, success, error, complete) {
            requestHandler({
                url: url,
                type: 'post',
                data: data,
                dataType:'json',
                timeout: 10000,
                contentType: "application/json",
                success: success,
                error: error,
                complete: complete
            })
        }

        /**
         * @Description: 处理Get请求
         * @param url
         * @param data
         * @param success
         * @param error
         * @param complete
         */
        function handleGet (url, data, success, error, complete) {
            requestHandler({
                url: url,
                type: 'post',
                data: data,
                dataType:'json',
                timeout: 10000,
                contentType: "application/json",
                success: success,
                error: error,
                complete: complete
            })
        }

        __initialize()
        return {
            post: handlePost,
            get: handleGet
        }
    })();

    /**
     * @Description: 封装Captcha
     */
    const Captcha = (function () {
        /**
         * @Description: 唯一KEY值，用作验证使用
         */
        var captchaKey = ""
        /**
         * @Description: 用户鼠标点击的位置 x,y
         */
        var dots = []
        /**
         * @Description: 最大可点数
         */
        var maxDot = 8

        const captchaWrapDom        = document.querySelector("#wg-cap-dots")
        const captchaImageDom       = document.querySelector("#wg-cap-image")
        const captchaThumbDom       = document.querySelector("#wg-cap-thumb")
        const captchaBtnControlDom  = document.querySelector("#wg-cap-btn-control")
        const captchaCheckBtnDom    = document.querySelector("#wg-cap-check-btn")
        const captchaCloseBtnDom    = document.querySelector("#wg-cap-close-btn")
        const captchaDialogBtnDom   = document.querySelector("#wg-cap-dialog")
        const captchaRefreshBtnDom  = document.querySelector("#wg-cap-refresh-btn")
        const captchaDefaultBtnDom  = document.querySelector("#wg-cap-btn-default")
        const captchaErrorBtnDom    = document.querySelector("#wg-cap-btn-error")
        const captchaOverBtnDom     = document.querySelector("#wg-cap-btn-over")
        const dialogDom             = document.querySelector("#wg-cap-container")

        /**
         * @Description: 初始化
         */
        function __initialize() {
            requestCaptchaData()
            handleEvent()

            // 禁用移动端缩放
            document.addEventListener('touchstart', (event) => {
                if (event.touches.length > 1) {
                    event.preventDefault()
                }
            })
            document.addEventListener('gesturestart', (event) => {
                event.preventDefault()
            })
            // touchstart  解决:hover伪类在移动端二次点击的问题
            document.body.addEventListener('touchend', () => { })
        }

        /**
         * @Description: 处理所有事件
         */
        function handleEvent() {
            addEventListener(captchaImageDom, "click", handleClickPos)
            addEventListener(captchaCheckBtnDom, "click", handleClickCheck)
            addEventListener(captchaCloseBtnDom, "click", handleClickClose)
            addEventListener(captchaDialogBtnDom, "click", handleClickClose)
            addEventListener(captchaRefreshBtnDom, "click", handleClickRefresh)
            addEventListener(captchaDefaultBtnDom, "click", handleClickDefault)
            addEventListener(captchaErrorBtnDom, "click", handleClickDefault)
            addEventListener(captchaOverBtnDom, "click", handleClickDefault)
        }

        /**
         * @Description: 为任意元素.绑定任意的事件
         * @param el    任意的元素
         * @param type  事件的类型
         * @param fn    事件处理函数
         */
        function addEventListener(el,type,fn) {
            //判断浏览器是否支持这个方法
            if(el.addEventListener){
                el.addEventListener(type,fn,false);
            }else if(el.attachEvent){
                el.attachEvent("on"+type,fn);
            }else{
                el["on"+type]=fn;
            }
        }

        /**
         * @Description: 找到元素的屏幕位置
         * @param el
         */
        function calcLocationLeft(el){
            var tmp = el.offsetLeft
            var val = el.offsetParent
            while(val != null){
                tmp += val.offsetLeft
                val = val.offsetParent
            }
            return tmp
        }

        /**
         * @Description: 找到元素的屏幕位置
         * @param el
         */
        function calcLocationTop(el){
            var tmp = el.offsetTop
            var val = el.offsetParent
            while(val != null){
                tmp += val.offsetTop
                val = val.offsetParent
            }
            return tmp
        }

        /**
         * @Description: 找到元素的屏幕位置
         * @param dom
         */
        function getDomXY(dom){
            var x = 0
            var y = 0
            if (dom.getBoundingClientRect) {
                var box = dom.getBoundingClientRect();
                var D = document.documentElement;
                x = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft;
                y = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop
            }
            else{
                while (dom !== document.body) {
                    x += dom.offsetLeft
                    y += dom.offsetTop
                    dom = dom.offsetParent
                }
            }
            return {
                domX: x,
                domY: y
            }
        }

        /**
         * @Description: 插入点击icon大小为22x22
         * @param event
         * @param x
         * @param y
         */
        function appendDotIcon(event, x, y) {
            // const icon = '<div class="wg-cap-wrap__dot" style="position:absolute; top:' + (y * 0.5) + 'px; left:' + (x * 0.5) + 'px;"><span>'+ (dots.length + 1) +'</span></div>'
            const dot = document.createElement('div')
            dot.setAttribute('class', 'wg-cap-wrap__dot')
            dot.setAttribute('style', 'top:' + (y - 11) + 'px; left:' + (x - 11) + 'px;')
            dot.innerHTML = '<span>'+ (dots.length + 1) +'</span>'
            captchaWrapDom.appendChild(dot)

            dots.push([x, y])
        }

        /**
         * @Description: 重置
         */
        function resetCaptcha() {
            captchaKey = ""
            dots = []
            captchaWrapDom.innerHTML = ""
        }

        /**
         * @Description: 清空验证图片
         */
        function clearImage() {
            captchaImageDom.setAttribute("src", "")
            captchaThumbDom.setAttribute("src", "")
        }

        /**
         * @Description: 处理点击验证码图片位置
         * @param ev
         */
        function handleClickPos(ev){
            if (dots.length >= maxDot || captchaKey === "") {
                return
            }

            const e = ev || window.event;
            e.preventDefault()
            const dom = e.currentTarget

            const xy = getDomXY(dom)
            const domX = xy.domX
            const domY = xy.domY
            // ===============================================
            // @notice 如 getDomXY 不准确可尝试使用 calcLocationLeft 或 calcLocationTop
            // const domX = this.calcLocationLeft(dom)
            // const domY = this.calcLocationTop(dom)
            // ===============================================

            const mouseX = (navigator.appName === 'Netscape') ? e.pageX : e.x + document.body.scrollLeft
            const mouseY = (navigator.appName === 'Netscape') ? e.pageY : e.y+document.body.scrollTop

            // 计算点击的相对位置
            const xPos = mouseX - domX;
            const yPos = mouseY - domY;

            appendDotIcon(e, xPos, yPos)
            e.cancelBubble = true
            e.preventDefault()
            return false
        }

        /**
         * @Description: 点击刷新
         */
        function handleClickRefresh() {
            requestCaptchaData()
        }

        /**
         * @Description: 点击刷新
         */
        function handleClickClose() {
            dialogDom.classList.remove("wg-cap-dialog__active")
        }

        /**
         * @Description: 点击验证
         */
        function handleClickCheck() {
            var dotsA = []
            dots.forEach(function (value, key) {
                dotsA.push(value.join(","))
            })

            if (dotsA.length <= 0) {
                alert("请点选图案进行验证")
                return
            }

            requestCheckCaptchaData({'dots': dotsA.join(','), 'key': captchaKey})
        }

        /**
         * @Description: 点击验证按钮，弹窗
         */
        function handleClickDefault() {
            requestCaptchaData()
            dialogDom.classList.add("wg-cap-dialog__active")
        }

        /**
         * @Description: 请求验证码数据
         */
        function requestCaptchaData() {
            resetCaptcha()
            clearImage()
            captchaImageDom.classList.add("wg-cap-wrap__hidden")
            captchaThumbDom.classList.add("wg-cap-wrap__hidden")

            Ajax.get("/go_captcha_data", {}, function(data){
                if (data['code'] === 0) {
                    captchaImageDom.classList.remove("wg-cap-wrap__hidden")
                    captchaThumbDom.classList.remove("wg-cap-wrap__hidden")
                    captchaImageDom.setAttribute("src", data['image_base64'])
                    captchaThumbDom.setAttribute("src", data['thumb_base64'])
                    captchaKey = data['captcha_key']
                } else {
                    alert("请求验证码数据失败：" + data['message'])
                }
            }, function(e){
                console.log("请求验证码数据失败：" + e['message']);
            })
        }

        /**
         * @Description: 请求验证数据
         * @param dots
         */
        function requestCheckCaptchaData(dots) {
            Ajax.post("/go_captcha_check_data", dots, function(data){
                captchaBtnControlDom.classList.remove("wg-cap-active__default")
                captchaBtnControlDom.classList.remove("wg-cap-active__over")
                if (data['code'] === 0) {
                    alert("验证成功")
                    captchaBtnControlDom.classList.remove("wg-cap-active__error")
                    captchaBtnControlDom.classList.add("wg-cap-active__success")
                    setTimeout(function () {
                        handleClickClose()
                    }, 200)
                } else {
                    alert("验证失败")
                    captchaBtnControlDom.classList.remove("wg-cap-active__success")
                    captchaBtnControlDom.classList.add("wg-cap-active__error")
                }
            }, function(e){
                captchaBtnControlDom.classList.remove("wg-cap-active__default")
                captchaBtnControlDom.classList.remove("wg-cap-active__over")
                captchaBtnControlDom.classList.remove("wg-cap-active__success")
                captchaBtnControlDom.classList.add("wg-cap-active__error")
            }, function () {
                captchaKey = ""
            })
        }

        __initialize()
        return {}
    })();
</script>
</html>
